
package com.jf.cloud.combo.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.jf.cloud.api.auth.constant.SysTypeEnum;
import com.jf.cloud.api.product.bo.SpuSimpleBO;
import com.jf.cloud.api.product.feign.ShopCartFeignClient;
import com.jf.cloud.api.product.feign.SkuFeignClient;
import com.jf.cloud.api.product.feign.SpuFeignClient;
import com.jf.cloud.combo.bo.ComboSkuStatusChangeNotifyBO;
import com.jf.cloud.combo.bo.ComboSpuCountChangeNotifyBO;
import com.jf.cloud.combo.constant.ComboStatus;
import com.jf.cloud.combo.mapper.ComboMapper;
import com.jf.cloud.combo.mapper.ComboSpuMapper;
import com.jf.cloud.combo.mapper.ComboSpuSkuMapper;
import com.jf.cloud.combo.model.Combo;
import com.jf.cloud.combo.model.ComboSpu;
import com.jf.cloud.combo.service.ComboService;
import com.jf.cloud.combo.service.ComboSpuService;
import com.jf.cloud.combo.service.ComboSpuSkuService;
import com.jf.cloud.common.cache.constant.CacheNames;
import com.jf.cloud.common.cache.util.RedisUtil;
import com.jf.cloud.common.constant.StatusEnum;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.i18n.I18nMessage;
import com.jf.cloud.common.product.constant.SupplierDeliveryType;
import com.jf.cloud.common.product.dto.ComboDTO;
import com.jf.cloud.common.product.vo.ComboSpuSkuVO;
import com.jf.cloud.common.product.vo.ComboSpuVO;
import com.jf.cloud.common.product.vo.ComboVO;
import com.jf.cloud.common.product.vo.SpuVO;
import com.jf.cloud.common.product.vo.app.SkuAppVO;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.rocketmq.config.RocketMqConstant;
import com.jf.cloud.common.security.AuthUserContext;
import io.seata.spring.annotation.GlobalTransactional;
import ma.glasnost.orika.MapperFacade;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 套装
 *
 * @author zz
 * @date 2022-08-16 09:18:06
 */
@Service
public class ComboServiceImpl implements ComboService {

    @Autowired
    private ComboMapper comboMapper;
    @Autowired
    private ComboSpuService comboSpuService;
    @Autowired
    private ComboSpuSkuService comboSpuSkuService;
    @Autowired
    private ComboSpuMapper comboSpuMapper;
    @Autowired
    private SpuFeignClient spuFeignClient;
    @Autowired
    private MapperFacade mapperFacade;
    @Autowired
    private ComboSpuSkuMapper comboSpuSkuMapper;
    @Autowired
    private SkuFeignClient skuFeignClient;
    @Autowired
    private ShopCartFeignClient shopCartFeignClient;
    @Autowired
    private RocketMQTemplate comboSkuStatusTemplate;
    @Autowired
    private RocketMQTemplate comboDeleteOrDisabledTemplate;
    @Autowired
    private RocketMQTemplate comboSpuCountChangeTemplate;

    @Override
    public PageVO<ComboVO> page(PageDTO pageDTO, ComboDTO comboDTO) {
        comboDTO.setShopId(AuthUserContext.get().getTenantId());
        if (Objects.nonNull(comboDTO.getMainSpuName()) && !Objects.equals(comboDTO.getMainSpuName(), "")) {
            //根据主商品查找商品id
            Set<Long> mainSpuIdList = getSpuIdByName(comboDTO.getMainSpuName());
            if (mainSpuIdList.size() == 0) {
                mainSpuIdList.add(-1L);
            }
            comboDTO.setMainSpuIdList(mainSpuIdList);
        }
        if (Objects.nonNull(comboDTO.getMatchSpuName()) && !Objects.equals(comboDTO.getMatchSpuName(), "")) {
            //根据搭配商品名称查找商品id
            Set<Long> matchSpuIdList = getSpuIdByName(comboDTO.getMatchSpuName());
            if (matchSpuIdList.size() == 0) {
                matchSpuIdList.add(-1L);
            }
            comboDTO.setMatchSpuIdList(matchSpuIdList);
        }
        PageVO<ComboVO> page = PageUtil.doPage(pageDTO, () -> comboMapper.list(comboDTO));
        Set<Long> mainSpuIdSet = page.getList().stream().map(ComboVO::getMainSpuId).collect(Collectors.toSet());
        ServerResponseEntity<List<SpuVO>> mainSpuResponseEntity = spuFeignClient.listSpuBySpuIds(new ArrayList<>(mainSpuIdSet));
        if (CollUtil.isEmpty(mainSpuResponseEntity.getData())) {
            return page;
        }
        Map<Long, String> spuNameMap = mainSpuResponseEntity.getData().stream().collect(Collectors.toMap(SpuVO::getSpuId, SpuVO::getName));
        Map<Long, String> imgUrlMap = mainSpuResponseEntity.getData().stream().collect(Collectors.toMap(SpuVO::getSpuId, SpuVO::getMainImgUrl));
        for (ComboVO comboVo : page.getList()) {
            comboVo.setMainSpuName(spuNameMap.get(comboVo.getMainSpuId()));
            comboVo.setMainSpuImgUrl(imgUrlMap.get(comboVo.getMainSpuId()));
        }
        return page;
    }

    /**
     * 根据商品名称模糊查找获取商品id列表
     *
     * @param name
     * @return
     */
    private Set<Long> getSpuIdByName(String name) {
        SpuSimpleBO spuSimpleBO = new SpuSimpleBO();
        spuSimpleBO.setSpuName(name);
        spuSimpleBO.setSeq(1);
        spuSimpleBO.setLang(I18nMessage.getLang());
        ServerResponseEntity<List<SpuSimpleBO>> spuRes = spuFeignClient.listSimple(spuSimpleBO);
        if (spuRes.isFail()) {
            throw new LuckException(spuRes.getMsg());
        }
        Set<Long> spuIds = new HashSet<>();
        if (CollUtil.isNotEmpty(spuRes.getData())) {
            spuIds = spuRes.getData().stream().map(SpuSimpleBO::getSpuId).collect(Collectors.toSet());
        }
        return spuIds;
    }

    @Override
    public ComboVO getByComboId(Long comboId, Integer sysType) {
        //获取套餐信息
        ComboVO comboVO = comboMapper.getByComboId(comboId);
        if (Objects.isNull(comboVO) || Objects.equals(comboVO.getStatus(), -1)) {
            throw new LuckException("套餐信息已不存在");
        }
        //获取主套餐商品信息
        mainSpuMsg(comboVO);
        //获取搭配套餐商品信息
        matchSpuMsg(comboVO, sysType);
        return comboVO;
    }

    @Override
    public ComboVO pcGetCombo(ComboDTO comboDTO, Integer sysType) {
        //获取套餐信息
        ComboVO comboVO = comboMapper.getByComboId(comboDTO.getComboId());
        if (Objects.isNull(comboVO)) {
            throw new LuckException("套餐信息已不存在");
        }
        //获取主套餐商品信息
        mainSpuMsg(comboVO);
        //获取搭配套餐商品信息
        matchSpuMsg(comboVO, sysType);
        //过滤搭配商品
        Set<Long> matchSpuIdList = comboDTO.getMatchSpuIdList();
        List<ComboSpuVO> matchingSpus = comboVO.getMatchingSpus();
        Iterator<ComboSpuVO> iterator = matchingSpus.iterator();
        while (iterator.hasNext()) {
            ComboSpuVO next = iterator.next();
            boolean contains = matchSpuIdList.contains(next.getSpuId());
            if (!contains) {
                iterator.remove();
            }
        }
        return comboVO;
    }

    /**
     * 主商品信息
     *
     * @param comboVO
     */
    private void mainSpuMsg(ComboVO comboVO) {
        //获取主套餐商品信息
        SpuVO mainSpuVo = spuFeignClient.getDetailById(comboVO.getMainSpuId()).getData();
        ComboSpuVO mainComboSpu = comboSpuMapper.getBySpuId(comboVO.getMainSpuId(), comboVO.getComboId());
        mainComboSpu.setPic(mainSpuVo.getMainImgUrl());
        mainComboSpu.setSpuName(mainSpuVo.getName());
        List<ComboSpuSkuVO> comboSpuSkuList = comboSpuSkuMapper.getByComboSpuIdS(mainComboSpu.getComboSpuId());
        //sku套餐最低价
        long minPrice = comboSpuSkuList.stream().mapToLong(e -> e.getMatchingPrice()).min().getAsLong();
        mainComboSpu.setComboPrice(minPrice);
        List<SkuAppVO> skuList = skuFeignClient.listBySpuId(mainSpuVo.getSpuId()).getData();
        //供应商发货
        List<SkuAppVO> supplierSkus = new ArrayList<>();
        if (Objects.nonNull(mainSpuVo.getSupplierSpuType()) && Objects.equals(mainSpuVo.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
            ServerResponseEntity<List<SkuAppVO>> supplierSkuResponse = skuFeignClient.listBySpuId(mainSpuVo.getSupplierSpuId());
            supplierSkus = supplierSkuResponse.getData();

        }
        for (SkuAppVO skuAppVO : skuList) {
            if (Objects.isNull(skuAppVO.getSkuName())) {
                skuAppVO.setSkuName("");
            }
            if (Objects.isNull(skuAppVO.getImgUrl())) {
                skuAppVO.setMainImgUrl("");
            }
        }
        Map<Long, SkuAppVO> skuAppMap = skuList.stream().collect(Collectors.toMap(SkuAppVO::getSkuId, e -> e));
        Map<Long, SkuAppVO> supplierSkuMap = supplierSkus.stream().collect(Collectors.toMap(SkuAppVO::getSkuId, e -> e));
        for (ComboSpuSkuVO comboSpuSkuVO : comboSpuSkuList) {
            SkuAppVO skuAppVO = skuAppMap.get(comboSpuSkuVO.getSkuId());
            if (Objects.isNull(skuAppVO)) {
                continue;
            }
            comboSpuSkuVO.setSkuName(skuAppVO.getSkuName());
            comboSpuSkuVO.setPriceFee(skuAppVO.getPriceFee());
            comboSpuSkuVO.setProperties(skuAppVO.getProperties());
            //供应商发货的代销商品显示供应商的库存
            comboSpuSkuVO.setStocks(Objects.equals(mainSpuVo.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value()) ? supplierSkuMap.get(skuAppVO.getSupplierSkuId()).getStock() : skuAppVO.getStock());
            comboSpuSkuVO.setPic(skuAppVO.getImgUrl());
        }
        mainComboSpu.setSkuList(comboSpuSkuList);
        comboVO.setMainSpu(mainComboSpu);
    }

    /**
     * 搭配商品信息
     *
     * @param comboVO
     */
    private void matchSpuMsg(ComboVO comboVO, Integer sysType) {
        //获取搭配套餐商品信息
        List<ComboSpuVO> matchingSpuList;
        //获取搭配套餐商品信息
        if (Objects.equals(sysType, SysTypeEnum.MULTISHOP.value())) {
            matchingSpuList = comboSpuMapper.matchingSpuByComboId(comboVO.getComboId(), StatusEnum.DELETE.value());
        } else {
            matchingSpuList = comboSpuMapper.matchingSpuByComboId(comboVO.getComboId(), StatusEnum.DISABLE.value());
        }
        List<Long> matchingSpuIds = matchingSpuList.stream().map(e -> e.getSpuId()).collect(Collectors.toList());
        //搭配套餐商品基本信息
        List<SpuVO> spuList = spuFeignClient.listSpuBySpuIds(matchingSpuIds).getData();

        if (Objects.isNull(spuList) || spuList.size() == 0) {
            return;
        }
        // 用户端商品是下架状态不显示
        if (Objects.equals(sysType, SysTypeEnum.ORDINARY.value())) {
            Map<Long, Integer> spuStatusMap = spuList.stream().collect(Collectors.toMap(SpuVO::getSpuId, SpuVO::getStatus));
            Iterator<ComboSpuVO> comboSpuIterator = matchingSpuList.iterator();
            while (comboSpuIterator.hasNext()) {
                ComboSpuVO comboSpuVO = comboSpuIterator.next();
                if (spuStatusMap.get(comboSpuVO.getSpuId()) != 1) {
                    comboSpuIterator.remove();
                }
            }
        }
        List<Long> matchingComboSpuIds = matchingSpuList.stream().map(e -> e.getComboSpuId()).collect(Collectors.toList());
        if (matchingComboSpuIds.size() == 0) {
            return;
        }
        //商品名字
        Map<Long, String> spuName = spuList.stream().collect(Collectors.toMap(SpuVO::getSpuId, SpuVO::getName));
        //商品图片
        Map<Long, String> spuImage = spuList.stream().collect(Collectors.toMap(SpuVO::getSpuId, SpuVO::getMainImgUrl));
        List<ComboSpuSkuVO> matchingComboSpuSkuVos = comboSpuSkuMapper.batchByComboSpuId(matchingComboSpuIds);
        Map<Long, List<ComboSpuSkuVO>> matchingComboSpuSkuVoGroup = matchingComboSpuSkuVos.stream().collect(Collectors.groupingBy(ComboSpuSkuVO::getComboSpuId));
        for (ComboSpuVO comboSpuVO : matchingSpuList) {
            comboSpuVO.setSpuName(spuName.get(comboSpuVO.getSpuId()));
            comboSpuVO.setPic(spuImage.get(comboSpuVO.getSpuId()));
            List<ComboSpuSkuVO> comboSpuSkuVO = matchingComboSpuSkuVoGroup.get(comboSpuVO.getComboSpuId());
            long minPrice = comboSpuSkuVO.stream().mapToLong(e -> e.getMatchingPrice()).min().getAsLong();
            comboSpuVO.setComboPrice(minPrice);
            List<SkuAppVO> matchingSkuList = skuFeignClient.listBySpuId(comboSpuVO.getSpuId()).getData();
            for (SkuAppVO matchingSkuVO : matchingSkuList) {
                if (Objects.isNull(matchingSkuVO.getSkuName())) {
                    matchingSkuVO.setSkuName("");
                }
                if (Objects.isNull(matchingSkuVO.getMainImgUrl())) {
                    matchingSkuVO.setMainImgUrl("");
                }
            }
            Map<Long, SkuAppVO> skuAppMap = matchingSkuList.stream().collect(Collectors.toMap(SkuAppVO::getSkuId, e -> e));
            for (ComboSpuSkuVO spuSkuVO : comboSpuSkuVO) {
                SkuAppVO skuAppVO = skuAppMap.get(spuSkuVO.getSkuId());
                if (Objects.isNull(skuAppVO)) {
                    continue;
                }
                spuSkuVO.setSkuName(skuAppVO.getSkuName());
                spuSkuVO.setPriceFee(skuAppVO.getPriceFee());
                spuSkuVO.setProperties(skuAppVO.getProperties());
                spuSkuVO.setStocks(skuAppVO.getStock());
                spuSkuVO.setPic(skuAppVO.getMainImgUrl());
            }
            comboSpuVO.setSkuList(comboSpuSkuVO);

        }
        comboVO.setMatchingSpus(matchingSpuList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = CacheNames.SPU_COMBO, key = "#comboDTO.getMainSpu().spuId")
    public void save(ComboDTO comboDTO) {
        //保存套餐信息
        Combo combo = new Combo();
        combo.setStartTime(comboDTO.getStartTime());
        combo.setEndTime(comboDTO.getEndTime());
        combo.setName(comboDTO.getName());
        combo.setMainSpuId(comboDTO.getMainSpu().getSpuId());
        Long price = loadComboPrice(comboDTO);
        combo.setPrice(price);
        combo.setSoldNum(0);
        combo.setShopId(comboDTO.getShopId());
        Date date = new Date();
        Date startTime = comboDTO.getStartTime();
        if (startTime.compareTo(date) > 0) {
            combo.setStatus(ComboStatus.NOT_STARTED.value());
        } else {
            combo.setStatus(ComboStatus.NORMAL.value());
        }
        comboMapper.save(combo);
        //保存套餐商品项信息
        ComboSpuVO mainSpuVo = comboDTO.getMainSpu();
        List<ComboSpuSkuVO> skuList = mainSpuVo.getSkuList();
        Long mainPrice = 0L;
        for (ComboSpuSkuVO comboSpuSkuVO : skuList) {
            mainPrice += comboSpuSkuVO.getMatchingPrice() * mainSpuVo.getLeastNum();
        }
        mainSpuVo.setComboPrice(mainPrice);
        mainSpuVo.setComboId(combo.getComboId());
        mainSpuVo.setType(1);
        mainSpuVo.setStatus(combo.getStatus());
        ComboSpu mainSpu = mapperFacade.map(mainSpuVo, ComboSpu.class);
        comboSpuService.save(mainSpu);
        // 保存主商品关联的规格信息
        comboSpuSkuService.insertBatch(mainSpuVo.getSkuList(), mainSpu.getComboSpuId());
        // 保存搭配商品和搭配商品关联的规格信息
        for (ComboSpuVO matchingSpu : comboDTO.getMatchingSpus()) {
            matchingSpu.setComboId(combo.getComboId());
            matchingSpu.setStatus(combo.getStatus());
        }
        comboSpuService.insertBatch(comboDTO.getMatchingSpus(), combo.getComboId());


    }

    private Long loadComboPrice(ComboDTO comboDTO) {
        Long price = 0L;
        ComboSpuVO mainSpu = comboDTO.getMainSpu();
        List<ComboSpuSkuVO> skuList = mainSpu.getSkuList();
        //主商品sku最低价
        Long mainPrice = skuList.stream().mapToLong(e -> e.getMatchingPrice()).min().getAsLong();

        price = mainPrice * mainSpu.getLeastNum();
        List<ComboSpuVO> matchingSpus = comboDTO.getMatchingSpus();
        for (ComboSpuVO comboSpuVO : matchingSpus) {
            List<ComboSpuSkuVO> skuListS = comboSpuVO.getSkuList();
            Long matchPrice = skuListS.stream().mapToLong(e -> e.getMatchingPrice()).min().getAsLong();
            price = price + (matchPrice * comboSpuVO.getLeastNum());
        }
        return price;

    }

    private void loadMatchingPrice(ComboSpuVO comboSpuVO) {
        comboSpuVO.setComboPrice(comboSpuVO.getSkuList().get(0).getMatchingPrice());
        for (ComboSpuSkuVO comboSpuSkuVO : comboSpuVO.getSkuList()) {
            if (comboSpuSkuVO.getMatchingPrice() < comboSpuVO.getComboPrice()) {
                comboSpuVO.setComboPrice(comboSpuSkuVO.getMatchingPrice());
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void update(ComboDTO comboDTO) {
        comboDTO.setMainSpuId(comboDTO.getMainSpu().getSpuId());
        //重新计算套餐价格
        comboDTO.setPrice(loadComboPrice(comboDTO));
        //更新套餐表数据
        Combo combo = mapperFacade.map(comboDTO, Combo.class);
        comboStatus(combo);
        comboMapper.update(combo);
        comboDTO.setStatus(combo.getStatus());
        //===========  更新主商品信息 ==============
        updateMainSpu(comboDTO);

        //===========  更新搭配商品信息 ============
        updateMatchSpu(comboDTO);
        // 更新redis中套餐的过期时间
        RedisUtil.set(CacheNames.ORDER_COMBO_EXPIRATION_TIME + comboDTO.getComboId(), comboDTO.getEndTime().getTime(), 3600);
    }


    private void comboStatus(Combo combo) {
        Date now = new Date();
        Date startTime = combo.getStartTime();
        if (startTime.compareTo(now) > 0) {
            //活动开始时间在当前时间后面
            combo.setStatus(ComboStatus.NOT_STARTED.value());
        } else {
            combo.setStatus(ComboStatus.NORMAL.value());
        }
        //如果套餐状态变为未开始状态则需要移除用户购物车
        if (Objects.equals(combo.getStatus(), ComboStatus.NOT_STARTED.value())) {
            List<Long> comboIdList = Arrays.asList(combo.getComboId());
            comboDeleteOrDisabledTemplate.syncSend(RocketMqConstant.COMBO_DELETE_OR_DISABLED, new GenericMessage<>(comboIdList));
        }
    }


    /**
     * 主商品更新
     *
     * @param comboDTO
     */
    private void updateMainSpu(ComboDTO comboDTO) {
        // 套餐主商品spuId集合
        List<Long> spuIdList = new ArrayList<>();
        // 把原有的主商品状态改为删除
        ComboSpuVO beforeComboSpuVo = comboSpuMapper.getMainSpuByComboId(comboDTO.getComboId());
        spuIdList.add(beforeComboSpuVo.getSpuId());
        // 获取删除前的主商品sku信息
        List<ComboSpuSkuVO> beforeSpuSkuList = comboSpuSkuService.comboVoListByComboSpuId(beforeComboSpuVo.getComboSpuId());
        ComboSpu comboSpu = new ComboSpu();
        comboSpu.setSpuId(beforeComboSpuVo.getSpuId());
        comboSpu.setStatus(ComboStatus.DELETE.value());
        comboSpu.setComboId(comboDTO.getComboId());
        comboSpuMapper.updateStatus(comboSpu);
        // 插入新的spu信息
        ComboSpuVO mainSpuVo = comboDTO.getMainSpu();
        spuIdList.add(mainSpuVo.getSpuId());
        List<ComboSpuSkuVO> skuList = mainSpuVo.getSkuList();
        Long mainPrice = 0L;
        for (ComboSpuSkuVO comboSpuSkuVO : skuList) {
            mainPrice += comboSpuSkuVO.getMatchingPrice() * mainSpuVo.getLeastNum();
        }
        mainSpuVo.setComboPrice(mainPrice);
        mainSpuVo.setComboId(comboDTO.getComboId());
        mainSpuVo.setType(1);
        mainSpuVo.setStatus(StatusEnum.ENABLE.value());
        ComboSpu mainSpu = mapperFacade.map(mainSpuVo, ComboSpu.class);
        mainSpu.setStatus(comboDTO.getStatus());
        comboSpuService.save(mainSpu);

        // 删除旧的sku信息
        ComboSpuVO nowComboSpuVo = comboSpuMapper.getMainSpuByComboId(comboDTO.getComboId());
        comboSpuSkuService.deleteBatch(Arrays.asList(beforeComboSpuVo.getComboSpuId()));
        // 插入新的sku信息
        List<ComboSpuSkuVO> spuSkuList = comboDTO.getMainSpu().getSkuList();
        // 同步状态
        for (ComboSpuSkuVO comboSpuSkuVO : spuSkuList) {
            comboSpuSkuVO.setSkuStatus(comboDTO.getStatus());
        }
        comboSpuSkuService.save(spuSkuList, nowComboSpuVo.getComboSpuId());

        // 套餐移除的sku时，同步移除用户购物车中的套餐sku商品
        List<Long> beforeSkuIdList = beforeSpuSkuList.stream().map(e -> e.getSkuId()).collect(Collectors.toList());
        List<ComboSpuSkuVO> nowSpuSkuList = mainSpuVo.getSkuList();
        List<Long> nowSkuIdList = nowSpuSkuList.stream().map(e -> e.getSkuId()).collect(Collectors.toList());
        // 移除的sku集合
        removeShopCartComboSpuSku(beforeSkuIdList, nowSkuIdList, comboDTO, true);

        // 更新用户购物车套餐商品数量
        ComboSpuCountChangeNotifyBO changeNotifyBO = new ComboSpuCountChangeNotifyBO();
        changeNotifyBO.setComboId(comboDTO.getComboId());
        changeNotifyBO.setSpuId(mainSpu.getSpuId());
        changeNotifyBO.setCount(mainSpu.getLeastNum());
        SendStatus sendStatus = comboSpuCountChangeTemplate
                .syncSend(RocketMqConstant.COMBO_SPU_COUNT_CHANGE, new GenericMessage<>(Arrays.asList(changeNotifyBO))).getSendStatus();
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            // 消息发不出去就抛异常
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        removeSpuCache(spuIdList);
    }

    /**
     * 移除商品套餐信息缓存
     *
     * @param spuIdList
     */
    private void removeSpuCache(List<Long> spuIdList) {
        // 移除商品套餐信息缓存
        List<String> keys = new ArrayList<>();
        for (Long spuId : spuIdList) {
            keys.add(CacheNames.SPU_COMBO + CacheNames.UNION + spuId);
        }
        RedisUtil.del(keys);
    }

    /**
     * 搭配商品更新
     *
     * @param comboDTO
     */
    private void updateMatchSpu(ComboDTO comboDTO) {
        // 套餐商品id集合
        List<Long> spuIdList = new ArrayList<>();
        // 更新前的搭配商品信息
        List<ComboSpuVO> beforeMatchSpu = comboSpuMapper.getMatchSpuByComboId(comboDTO.getComboId());
        List<Long> beforeSpuIdS = beforeMatchSpu.stream().map(e -> e.getSpuId()).collect(Collectors.toList());
        spuIdList.addAll(beforeSpuIdS);
        List<Long> beforeMatchComboSpuIdS = beforeMatchSpu.stream().map(e -> e.getComboSpuId()).collect(Collectors.toList());
        // 前端传来的更新搭配商品信息
        List<ComboSpuVO> nowMatchSpu = comboDTO.getMatchingSpus();
        List<Long> nowSpuIdS = nowMatchSpu.stream().map(e -> e.getSpuId()).collect(Collectors.toList());
        spuIdList.addAll(nowSpuIdS);
        for (ComboSpuVO comboSpuVO : nowMatchSpu) {
            comboSpuVO.setStatus(comboDTO.getStatus());
        }
        // comboSpu数据删除旧的，插入新的
        if (beforeMatchComboSpuIdS.size() != 0) {
            comboSpuService.deleteBatch(beforeMatchComboSpuIdS);
        }
        comboSpuService.insertBatch(nowMatchSpu, comboDTO.getComboId());
        // 获取插入后的数据
        // 移除购物车
        List<Long> beforeSkuIdList = new ArrayList<>();
        List<Long> nowSkuIdList = new ArrayList<>();
        for (ComboSpuVO spuVO : beforeMatchSpu) {
            List<ComboSpuSkuVO> byComboSpuId = comboSpuSkuMapper.getByComboSpuId(spuVO.getComboSpuId());
            if (byComboSpuId.size() == 0) {
                continue;
            }
            List<Long> skuIdList = byComboSpuId.stream().map(e -> e.getSkuId()).collect(Collectors.toList());
            beforeSkuIdList.addAll(skuIdList);
        }
        for (ComboSpuVO spuVO : nowMatchSpu) {
            List<Long> skuIdList = spuVO.getSkuList().stream().map(e -> e.getSkuId()).collect(Collectors.toList());
            nowSkuIdList.addAll(skuIdList);
        }
        //comboSpuSku数据删除旧的，插入新的
        if (beforeMatchComboSpuIdS.size() != 0) {
            comboSpuSkuService.deleteBatch(beforeMatchComboSpuIdS);
        }
        removeShopCartComboSpuSku(beforeSkuIdList, nowSkuIdList, comboDTO, false);

        // 修改套餐商品起搭数时更新用户购物车套餐商品数量
        ComboSpuCountChangeNotifyBO changeNotifyBO;
        List<ComboSpuCountChangeNotifyBO> comboSpuCountChangeNotifyBOList = new ArrayList<>();
        for (ComboSpuVO comboSpuVO : nowMatchSpu) {
            changeNotifyBO = new ComboSpuCountChangeNotifyBO();
            changeNotifyBO.setComboId(comboDTO.getComboId());
            changeNotifyBO.setSpuId(comboSpuVO.getSpuId());
            changeNotifyBO.setCount(comboSpuVO.getLeastNum());
            comboSpuCountChangeNotifyBOList.add(changeNotifyBO);
        }
        SendStatus sendStatus = comboSpuCountChangeTemplate
                .syncSend(RocketMqConstant.COMBO_SPU_COUNT_CHANGE, new GenericMessage<>(comboSpuCountChangeNotifyBOList)).getSendStatus();
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            // 消息发不出去就抛异常
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        // 移除商品套餐信息缓存
        removeSpuCache(spuIdList);
    }


    /**
     * 计算出移除的skuId，同时移除用户购物车
     *
     * @param beforeSkuIdList
     * @param nowSkuIdList
     * @param comboDTO
     */
    private void removeShopCartComboSpuSku(List<Long> beforeSkuIdList, List<Long> nowSkuIdList, ComboDTO comboDTO, Boolean isMainSpu) {
        //移除的sku集合
        List<Long> removeSkuIdList = new ArrayList<>();
        for (Long skuId : beforeSkuIdList) {
            if (!nowSkuIdList.contains(skuId)) {
                removeSkuIdList.add(skuId);
            }
        }
        //主商品sku移除时，对应的搭配商品也要移除
        if (isMainSpu) {
            if (removeSkuIdList.size() != 0) {
                //需要移除的搭配商品skuId
                List<Long> matchSkuIdList = shopCartFeignClient.skuIdListByComboMainSkuId(removeSkuIdList).getData();
                removeSkuIdList.addAll(matchSkuIdList);
            }
        }
        ComboSkuStatusChangeNotifyBO changeNotifyBO = new ComboSkuStatusChangeNotifyBO();
        changeNotifyBO.setComboId(comboDTO.getComboId());
        changeNotifyBO.setSkuList(removeSkuIdList);
        //发送消息移除用户购物车
        comboSkuStatusTemplate.syncSend(RocketMqConstant.COMBO_SKU_STATUS_TOPIC, new GenericMessage<>(changeNotifyBO));
    }

    /**
     * 计算套餐单个商品总价
     *
     * @param comboSpu
     * @return
     */
    private Long calculatePrice(ComboSpu comboSpu) {
        Long price = 0L;
        List<ComboSpuSkuVO> skuList = comboSpu.getSkuList();
        for (ComboSpuSkuVO comboSpuSkuVO : skuList) {
            price += price + comboSpuSkuVO.getMatchingPrice() * comboSpu.getLeastNum();
        }
        return price;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void updateComboStatus(Long comboId, Integer status) {
        // 主商品
        ComboSpuVO mainSpu = comboSpuMapper.getMainComboSpuId(comboId);
        // 修改套餐状态
        comboMapper.updateComboStatus(comboId, status);
        // 修改套餐商品项状态
        ComboSpu comboSpu = new ComboSpu();
        comboSpu.setStatus(status);
        comboSpu.setComboId(comboId);
        comboSpuMapper.updateStatus(comboSpu);
        List<Long> comboSpuIdList = new ArrayList<>();
        // 套餐商品id集合
        List<Long> spuIdList = new ArrayList<>();
        // 搭配商品
        List<ComboSpuVO> matchSpuByComboId = comboSpuMapper.getMatchSpuByComboId(comboId);
        List<Long> matchSpuIdList = matchSpuByComboId.stream().map(e -> e.getSpuId()).collect(Collectors.toList());
        spuIdList.addAll(matchSpuIdList);
        List<Long> matchComboSpuIdList = matchSpuByComboId.stream().map(e -> e.getComboSpuId()).collect(Collectors.toList());
        comboSpuIdList.addAll(matchComboSpuIdList);
        comboSpuIdList.add(mainSpu.getComboSpuId());
        spuIdList.add(mainSpu.getSpuId());
        comboSpuSkuMapper.batchUpdateByComboSpuIdList(comboSpuIdList, status);
        // 失效或者删除套餐时移除购物车商品
        List<Long> comboIdList = Arrays.asList(comboId);
        shopCartFeignClient.deleteCartByComboUpdate(comboIdList, -1L, -1L);
//        SendResult sendStatus = comboDeleteOrDisabledTemplate.syncSend(RocketMqConstant.COMBO_DELETE_OR_DISABLED, new GenericMessage<>(comboIdList));
//        if (!Objects.equals(sendStatus,SendStatus.SEND_OK)) {
//            // 消息发不出去就抛异常
//            throw new LuckException(ResponseEnum.EXCEPTION);
//        }
        // 移除商品套餐信息缓存
        removeSpuCache(spuIdList);
        RedisUtil.set(CacheNames.ORDER_COMBO_STATUS + comboId, status, 3600);

    }

    @Override
    @Cacheable(cacheNames = CacheNames.SPU_COMBO, key = "#spuId")
    public List<ComboVO> comboVoListBySpuId(Long spuId) {
        List<ComboVO> comboList = comboMapper.comboVoListBySpuId(spuId);
        if (comboList.size() == 0) {
            return null;
        }
        List<Long> idList = new ArrayList<>();
        for (ComboVO comboVO : comboList) {
            List<Long> ids = comboVO.getMatchingSpus().stream().map(ComboSpuVO::getSpuId).collect(Collectors.toList());
            idList.addAll(ids);
        }
        List<SpuVO> spuList = spuFeignClient.listSpuBySpuIds(idList).getData();
        Map<Long, Integer> spuStatusMap = spuList.stream().collect(Collectors.toMap(SpuVO::getSpuId, SpuVO::getStatus));
        Iterator<ComboVO> iterator = comboList.iterator();
        while (iterator.hasNext()) {
            ComboVO comboVO = iterator.next();
            Long minPrice = 0L;
            Iterator<ComboSpuVO> spuIterator = comboVO.getMatchingSpus().iterator();
            while (spuIterator.hasNext()) {
                ComboSpuVO comboProdVO = spuIterator.next();
                comboProdVO.setSpuStatus(spuStatusMap.get(comboProdVO.getSpuId()));
                if (!Objects.equals(comboProdVO.getSpuStatus(), 1)) {
                    spuIterator.remove();
                    continue;
                }
                if (comboProdVO.getRequired() == 1 || comboProdVO.getType() == 1) {
                    minPrice = minPrice + comboProdVO.getComboPrice() * comboProdVO.getLeastNum();
                }
            }
            comboVO.setMatchingPrice(minPrice);
            if (CollUtil.isEmpty(comboVO.getMatchingSpus())) {
                iterator.remove();
            }
        }
        //根据套餐id分组
        Map<Long, List<ComboVO>> comboVoByComboId = comboList.stream().collect(Collectors.groupingBy(ComboVO::getComboId));
        for (List<ComboVO> value : comboVoByComboId.values()) {
            ComboVO comboVO = value.get(0);
            //处理商品信息
            disposeMatchSpu(comboVO);
            //套餐价格
            comboPrice(comboVO);
        }
        return comboList;
    }

    /**
     * 计算套餐价格
     *
     * @param comboVO
     */
    private void comboPrice(ComboVO comboVO) {
        //获取主商品最低sku套餐价格
        ComboSpuVO mainSpu = comboVO.getMainSpu();
        List<ComboSpuSkuVO> mainSpuSkuList = comboSpuSkuService.getByComboSpuId(mainSpu.getComboSpuId());
        long mainPrice = mainSpuSkuList.stream().mapToLong(e -> e.getMatchingPrice()).min().getAsLong() * mainSpu.getLeastNum();
        mainSpu.setComboPrice(mainPrice);
        //获取搭配商品最低sku套餐价格
        List<ComboSpuVO> matchingSpus = comboVO.getMatchingSpus();
        if (Objects.nonNull(matchingSpus) && matchingSpus.size() != 0) {
            List<Long> skuIsList = matchingSpus.stream().map(e -> e.getComboSpuId()).collect(Collectors.toList());
            List<ComboSpuSkuVO> comboSpuSkuVOList = comboSpuSkuService.comboSpuSkuList(skuIsList);
            Map<Long, List<ComboSpuSkuVO>> longListMap = comboSpuSkuVOList.stream().collect(Collectors.groupingBy(ComboSpuSkuVO::getComboSpuId));
            for (ComboSpuVO comboSpuVO : matchingSpus) {
                comboSpuVO.setSkuList(longListMap.get(comboSpuVO.getComboSpuId()));
                Long price = comboSpuVO.getSkuList().stream().mapToLong(e -> e.getMatchingPrice()).min().getAsLong() * comboSpuVO.getLeastNum();
                comboSpuVO.setComboPrice(price);
                if (Objects.equals(comboSpuVO.getRequired(), 1)) {
                    mainPrice += price;
                }
            }
        }
        comboVO.setMatchingPrice(mainPrice);
        comboVO.setPrice(mainPrice);
    }

    /**
     * 处理套餐主商品
     *
     * @param comboVO
     */
    private void disposeMainSpu(ComboVO comboVO) {
        //套餐主商品
        ComboSpuVO mainSpu = comboVO.getMainSpu();
        SpuVO spuVO = spuFeignClient.getById(mainSpu.getSpuId()).getData();
        mainSpu.setSpuName(spuVO.getName());
        mainSpu.setPic(spuVO.getMainImgUrl());
        mainSpu.setSpuStatus(spuVO.getStatus());
    }

    /**
     * 处理套餐搭配商品
     *
     * @param comboVO
     */
    private void disposeMatchSpu(ComboVO comboVO) {
        List<ComboSpuVO> matchingSpuS = comboVO.getMatchingSpus();
        List<Long> spuIdList = matchingSpuS.stream().map(e -> e.getSpuId()).collect(Collectors.toList());
        //获取商品基本信息
        List<SpuVO> spuVOList = spuFeignClient.listSpuBySpuIdsNo(spuIdList).getData();
        Map<Long, Integer> spuVoStatusMap = spuVOList.stream().collect(Collectors.toMap(SpuVO::getSpuId, SpuVO::getStatus));
        //根据商品id分组
        Map<Long, List<SpuVO>> spuVoBySpuId = spuVOList.stream().collect(Collectors.groupingBy(SpuVO::getSpuId));
        Iterator<ComboSpuVO> iterator = matchingSpuS.iterator();
        while (iterator.hasNext()) {
            ComboSpuVO comboSpuVO = iterator.next();
            //套餐商品只展示上架状态的
            if (spuVoStatusMap.get(comboSpuVO.getSpuId()) != 1) {
                iterator.remove();
                continue;
            }
            SpuVO vo = spuVoBySpuId.get(comboSpuVO.getSpuId()).get(0);
            comboSpuVO.setSpuName(vo.getName());
            comboSpuVO.setPic(vo.getMainImgUrl());
            comboSpuVO.setSpuStatus(vo.getStatus());
            //如果是主商品就移除到主商品集合中
            if (Objects.equals(comboSpuVO.getType(), 1)) {
                comboVO.setMainSpu(comboSpuVO);
                iterator.remove();
            }

        }
        //套餐商品数量  = 搭配商品数量 + 主商品数量(主商品只有一个)
        Integer comboSpuCount = comboVO.getMatchingSpus().size() + 1;
        comboVO.setSpuCount(comboSpuCount);
    }

    @Override
    public List<ComboVO> listComboInfoBySpuId(Long shopId, Long spuId) {
        return comboMapper.listComboInfoBySpuId(shopId, spuId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void comboEndOperation() {
        List<ComboVO> comboList = comboMapper.listUnEndButNeedEndActivity();
        if (comboList.size() == 0) {
            return;
        }
        //套餐id集合
        List<Long> comboIdList = comboList.stream().map(e -> e.getComboId()).collect(Collectors.toList());
        //修改套餐状态
        comboMapper.batchUpdateComboStatus(comboIdList, StatusEnum.DISABLE.value());
        //修改套餐商品sku项状态
        List<Long> comboSpuIdList = new ArrayList<>();
        for (ComboVO comboVO : comboList) {
            //搭配商品
            List<ComboSpuVO> matchSpuByComboId = comboSpuMapper.getMatchSpuByComboId(comboVO.getComboId());
            List<Long> matchComboSpuIdList = matchSpuByComboId.stream().map(e -> e.getComboSpuId()).collect(Collectors.toList());
            comboSpuIdList.addAll(matchComboSpuIdList);
            //主商品
            ComboSpuVO mainSpuByComboId = comboSpuMapper.getMainSpuByComboId(comboVO.getComboId());
            comboSpuIdList.add(mainSpuByComboId.getComboSpuId());
        }
        comboSpuSkuMapper.batchUpdateByComboSpuIdList(comboSpuIdList, StatusEnum.DISABLE.value());
        //移除购物车商品
        //失效或者删除套餐时移除购物车商品
        comboDeleteOrDisabledTemplate.syncSend(RocketMqConstant.COMBO_DELETE_OR_DISABLED, new GenericMessage<>(comboIdList));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void enableCombo() {
        //查询符合条件的套餐id
        List<ComboVO> comboList = comboMapper.notStartComboIdButStart();
        if (CollUtil.isNotEmpty(comboList)) {
            List<Long> comboIdList = comboList.stream().map(ComboVO::getComboId).collect(Collectors.toList());
            List<Long> comboMainSpuIdList = comboList.stream().map(ComboVO::getMainSpuId).collect(Collectors.toList());
            // 移除主商品套餐信息缓存
            removeSpuCache(comboMainSpuIdList);
            comboMapper.batchUpdateComboStatus(comboIdList, ComboStatus.NORMAL.value());
            // 根据套餐id改变套餐商品项状态
            comboSpuMapper.batchUpdateByComboIdList(comboIdList, ComboStatus.NORMAL.value());

            // 修改套餐商品sku项状态
            List<ComboSpuVO> comboSpuList = comboSpuMapper.comboSpuByComboIds(comboIdList);
            List<Long> comboSpuId = comboSpuList.stream().map(ComboSpuVO::getComboSpuId).collect(Collectors.toList());
            comboSpuSkuMapper.batchUpdateByComboSpuIdList(comboSpuId, ComboStatus.NORMAL.value());
        }
    }

    @Override
    public void comboSoldNumAdd(List<ComboDTO> comboList) {
        comboMapper.comboSoldNumAdd(comboList);
    }

    @Override
    @CacheEvict(cacheNames = CacheNames.SPU_COMBO, key = "#spuId")
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void offComboMainSpu(Long spuId) {
        //根据商品id获取正在进行中的套餐
        List<ComboVO> comboList = comboMapper.comboIdByMainSpuId(spuId, StatusEnum.ENABLE.value());
        // 获取未开始的套餐
        comboList.addAll(comboMapper.comboIdByMainSpuId(spuId, StatusEnum.OFFLINE.value()));
        if (comboList.size() == 0) {
            return;
        }
        //批量失效套餐活动
        List<Long> comboIdList = comboList.stream().map(e -> e.getComboId()).collect(Collectors.toList());
        comboMapper.batchUpdateComboStatus(comboIdList, StatusEnum.DISABLE.value());
        shopCartFeignClient.deleteCartByComboUpdate(comboIdList, -1L, -1L);
//        SendResult sendStatus = comboDeleteOrDisabledTemplate.syncSend(RocketMqConstant.COMBO_DELETE_OR_DISABLED, new GenericMessage<>(comboIdList));
//        if (!Objects.equals(sendStatus.getSendStatus(),SendStatus.SEND_OK)) {
//            // 消息发不出去就抛异常
//            throw new LuckException(ResponseEnum.EXCEPTION);
//        }
    }

    @Override
    public Boolean checkComboSpu(Long spuId,Long shopId) {
        //根据商品id获取正在进行中的套餐
        Integer checkComboSpu = comboMapper.checkComboSpu(spuId,shopId);
        boolean result = false;
        if (checkComboSpu > 0) {
            result = true;
        }
        return result;
    }

    @Override
    public Integer checkComboIsUsable(List<Long> comboIdList) {
        if (comboIdList.size() == 0) {
            return 0;
        }
        return comboMapper.checkComboIsUsable(comboIdList);
    }

    @Override
    public void removeComboSpuCache(Long spuId) {
        List<Long> mainSpuIdList = comboMapper.getComboMainSpuIdBySpuId(spuId);
        if (mainSpuIdList.size() != 0) {
            removeSpuCache(mainSpuIdList);
        }
    }

    @Override
    public List<ComboVO> getComboByComboIdList(List<Long> comboIdList) {
        return comboMapper.getComboByComboIdList(comboIdList);
    }
}
